🎖️GitЯра🎖️
Node / meshtastic / Meshtastic-Android / files / core / ui / src / commonTest / kotlin / org / meshtastic / core / ui / util / ProtoExtensionsTest.kt
Displaying Raw • Download
core/ui/src/commonTest/kotlin/org/meshtastic/core/ui/util/ProtoExtensionsTest.kt 9613ba91a7e169afe8ce2e98c6d384ef37f03421 (9613ba91) Text, 31.10 KB
T8b949e/*
* Copyright (c) 2026 Meshtastic LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
Tff7b72package T7ee787org.meshtastic.core.ui.util
Tff7b72import T7ee787kotlinx.coroutines.test.runTest
Tff7b72import T7ee787okio.ByteString.Companion.toByteString
Tff7b72import T7ee787org.meshtastic.core.testing.FakeRadioConfigRepository
Tff7b72import T7ee787org.meshtastic.core.testing.FakeRadioController
Tff7b72import T7ee787org.meshtastic.proto.Channel
Tff7b72import T7ee787org.meshtastic.proto.ChannelSet
Tff7b72import T7ee787org.meshtastic.proto.ChannelSettings
Tff7b72import T7ee787org.meshtastic.proto.Config
Tff7b72import T7ee787org.meshtastic.proto.LocalConfig
Tff7b72import T7ee787kotlin.test.Test
Tff7b72import T7ee787kotlin.test.assertEquals
Tff7b72import T7ee787kotlin.test.assertFailsWith
Tff7b72import T7ee787kotlin.test.assertFalse
Tff7b72import T7ee787kotlin.test.assertTrue
Tff7b72import T7ee787org.meshtastic.core.model.Channel Tff7b72as Te6edf3ModelChannel
T8b949e/**
* Coverage for [getChannelReplacementList]. The REPLACE helper must emit an authoritative slot list for QR imports:
* every imported index becomes a write (PRIMARY at 0, SECONDARY thereafter), and any trailing slots present in the
* cached set are emitted as DISABLED so the radio stops using them. Critically, positions where the cache already
* matches the import are NOT skipped — the diff-skip was the source of stale channels.
*/
Tff7b72class T56d364ProtoExtensionsTest Tb4b4b4{
Tf0883e@Test
Tff7b72fun Td2a8ffindex_zero_emits_primary_with_new_settings_even_when_unchanged_from_oldTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3same Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffMainTa5d6ff"Tb4b4b4, Te6edf3psk Tff7b72= Te6edf3byteArrayOfTb4b4b4(T79c0ff1Tb4b4b4, T79c0ff2Tb4b4b4, T79c0ff3Tb4b4b4)Tb4b4b4.Te6edf3toByteStringTb4b4b4(Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3result Tff7b72= Te6edf3getChannelReplacementListTb4b4b4(Te6edf3new Tff7b72= Te6edf3listOfTb4b4b4(Te6edf3sameTb4b4b4)Tb4b4b4, Te6edf3currentSettings Tff7b72= Te6edf3listOfTb4b4b4(Te6edf3sameTb4b4b4)Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff1Tb4b4b4, Te6edf3resultTb4b4b4.Te6edf3sizeTb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3ChannelTb4b4b4.Te6edf3RoleTb4b4b4.Te6edf3PRIMARYTb4b4b4, Te6edf3resultTb4b4b4.Te6edf3singleTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3roleTb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff0Tb4b4b4, Te6edf3resultTb4b4b4.Te6edf3singleTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3indexTb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3sameTb4b4b4, Te6edf3resultTb4b4b4.Te6edf3singleTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3settingsTb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffsecondary_indices_emit_secondary_with_new_settings_even_when_unchanged_from_oldTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3primary Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffMainTa5d6ff"Tb4b4b4)
Tff7b72val Te6edf3secondary Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffChatTa5d6ff"Tb4b4b4)
Tff7b72val Te6edf3result Tff7b72=
Te6edf3getChannelReplacementListTb4b4b4(Te6edf3new Tff7b72= Te6edf3listOfTb4b4b4(Te6edf3primaryTb4b4b4, Te6edf3secondaryTb4b4b4)Tb4b4b4, Te6edf3currentSettings Tff7b72= Te6edf3listOfTb4b4b4(Te6edf3primaryTb4b4b4, Te6edf3secondaryTb4b4b4)Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff2Tb4b4b4, Te6edf3resultTb4b4b4.Te6edf3sizeTb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3ChannelTb4b4b4.Te6edf3RoleTb4b4b4.Te6edf3PRIMARYTb4b4b4, Te6edf3resultTff7b72[T79c0ff0Tff7b72]Tb4b4b4.Te6edf3roleTb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3primaryTb4b4b4, Te6edf3resultTff7b72[T79c0ff0Tff7b72]Tb4b4b4.Te6edf3settingsTb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3ChannelTb4b4b4.Te6edf3RoleTb4b4b4.Te6edf3SECONDARYTb4b4b4, Te6edf3resultTff7b72[T79c0ff1Tff7b72]Tb4b4b4.Te6edf3roleTb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff1Tb4b4b4, Te6edf3resultTff7b72[T79c0ff1Tff7b72]Tb4b4b4.Te6edf3indexTb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3secondaryTb4b4b4, Te6edf3resultTff7b72[T79c0ff1Tff7b72]Tb4b4b4.Te6edf3settingsTb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffold_trailing_indices_beyond_new_are_emitted_as_disabled_with_empty_settingsTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3primary Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffMainTa5d6ff"Tb4b4b4)
Tff7b72val Te6edf3result Tff7b72=
Te6edf3getChannelReplacementListTb4b4b4(
Te6edf3new Tff7b72= Te6edf3listOfTb4b4b4(Te6edf3primaryTb4b4b4)Tb4b4b4,
Te6edf3currentSettings Tff7b72= Te6edf3listOfTb4b4b4(Te6edf3primaryTb4b4b4, Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffOldTa5d6ff"Tb4b4b4)Tb4b4b4)Tb4b4b4,
Tb4b4b4)
T8b949e// index 0 PRIMARY (new), index 1 DISABLED (trailing old slot)
Te6edf3assertEqualsTb4b4b4(T79c0ff2Tb4b4b4, Te6edf3resultTb4b4b4.Te6edf3sizeTb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3ChannelTb4b4b4.Te6edf3RoleTb4b4b4.Te6edf3PRIMARYTb4b4b4, Te6edf3resultTff7b72[T79c0ff0Tff7b72]Tb4b4b4.Te6edf3roleTb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3primaryTb4b4b4, Te6edf3resultTff7b72[T79c0ff0Tff7b72]Tb4b4b4.Te6edf3settingsTb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3ChannelTb4b4b4.Te6edf3RoleTb4b4b4.Te6edf3DISABLEDTb4b4b4, Te6edf3resultTff7b72[T79c0ff1Tff7b72]Tb4b4b4.Te6edf3roleTb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff1Tb4b4b4, Te6edf3resultTff7b72[T79c0ff1Tff7b72]Tb4b4b4.Te6edf3indexTb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3ChannelSettingsTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3resultTff7b72[T79c0ff1Tff7b72]Tb4b4b4.Te6edf3settingsTb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffempty_new_and_empty_old_produces_empty_listTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3result Tff7b72= Te6edf3getChannelReplacementListTb4b4b4(Te6edf3new Tff7b72= Te6edf3emptyListTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3currentSettings Tff7b72= Te6edf3emptyListTb4b4b4(Tb4b4b4)Tb4b4b4)
Te6edf3assertTrueTb4b4b4(Te6edf3resultTb4b4b4.Te6edf3isEmptyTb4b4b4(Tb4b4b4)Tb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffempty_new_with_non_empty_current_emits_disabled_for_every_current_indexTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3currentSettings Tff7b72=
Te6edf3listOfTb4b4b4(Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffATa5d6ff"Tb4b4b4)Tb4b4b4, Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffBTa5d6ff"Tb4b4b4)Tb4b4b4, Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffCTa5d6ff"Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3result Tff7b72= Te6edf3getChannelReplacementListTb4b4b4(Te6edf3new Tff7b72= Te6edf3emptyListTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3currentSettings Tff7b72= Te6edf3currentSettingsTb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff3Tb4b4b4, Te6edf3resultTb4b4b4.Te6edf3sizeTb4b4b4)
Te6edf3resultTb4b4b4.Te6edf3forEachIndexed Tb4b4b4{ Te6edf3iTb4b4b4, Te6edf3channel Tff7b72-Tff7b72>
Te6edf3assertEqualsTb4b4b4(Te6edf3ChannelTb4b4b4.Te6edf3RoleTb4b4b4.Te6edf3DISABLEDTb4b4b4, Te6edf3channelTb4b4b4.Te6edf3roleTb4b4b4, Ta5d6ff"Ta5d6ffindex Tffd700$Te6edf3iTa5d6ff should be DISABLEDTa5d6ff"Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3iTb4b4b4, Te6edf3channelTb4b4b4.Te6edf3indexTb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3ChannelSettingsTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3channelTb4b4b4.Te6edf3settingsTb4b4b4, Ta5d6ff"Ta5d6ffindex Tffd700$Te6edf3iTa5d6ff should carry empty settingsTa5d6ff"Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffsingle_entry_new_with_multi_entry_current_emits_primary_then_disabled_trailingTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3newPrimary Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffImportedTa5d6ff"Tb4b4b4)
Tff7b72val Te6edf3currentSettings Tff7b72=
Te6edf3listOfTb4b4b4(
Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffCurrentPrimaryTa5d6ff"Tb4b4b4)Tb4b4b4,
Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffCurrentSecondaryTa5d6ff"Tb4b4b4)Tb4b4b4,
Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffCurrentTertiaryTa5d6ff"Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Tff7b72val Te6edf3result Tff7b72= Te6edf3getChannelReplacementListTb4b4b4(Te6edf3new Tff7b72= Te6edf3listOfTb4b4b4(Te6edf3newPrimaryTb4b4b4)Tb4b4b4, Te6edf3currentSettings Tff7b72= Te6edf3currentSettingsTb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff3Tb4b4b4, Te6edf3resultTb4b4b4.Te6edf3sizeTb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3ChannelTb4b4b4.Te6edf3RoleTb4b4b4.Te6edf3PRIMARYTb4b4b4, Te6edf3resultTff7b72[T79c0ff0Tff7b72]Tb4b4b4.Te6edf3roleTb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff0Tb4b4b4, Te6edf3resultTff7b72[T79c0ff0Tff7b72]Tb4b4b4.Te6edf3indexTb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3newPrimaryTb4b4b4, Te6edf3resultTff7b72[T79c0ff0Tff7b72]Tb4b4b4.Te6edf3settingsTb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3ChannelTb4b4b4.Te6edf3RoleTb4b4b4.Te6edf3DISABLEDTb4b4b4, Te6edf3resultTff7b72[T79c0ff1Tff7b72]Tb4b4b4.Te6edf3roleTb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3ChannelTb4b4b4.Te6edf3RoleTb4b4b4.Te6edf3DISABLEDTb4b4b4, Te6edf3resultTff7b72[T79c0ff2Tff7b72]Tb4b4b4.Te6edf3roleTb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3ChannelSettingsTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3resultTff7b72[T79c0ff1Tff7b72]Tb4b4b4.Te6edf3settingsTb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3ChannelSettingsTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3resultTff7b72[T79c0ff2Tff7b72]Tb4b4b4.Te6edf3settingsTb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffnew_larger_than_old_emits_primary_plus_secondaries_for_every_new_indexTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3primary Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffMainTa5d6ff"Tb4b4b4)
Tff7b72val Te6edf3secondaryA Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffChatTa5d6ff"Tb4b4b4)
Tff7b72val Te6edf3secondaryB Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffDataTa5d6ff"Tb4b4b4)
Tff7b72val Te6edf3result Tff7b72=
Te6edf3getChannelReplacementListTb4b4b4(Te6edf3new Tff7b72= Te6edf3listOfTb4b4b4(Te6edf3primaryTb4b4b4, Te6edf3secondaryATb4b4b4, Te6edf3secondaryBTb4b4b4)Tb4b4b4, Te6edf3currentSettings Tff7b72= Te6edf3listOfTb4b4b4(Te6edf3primaryTb4b4b4)Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff3Tb4b4b4, Te6edf3resultTb4b4b4.Te6edf3sizeTb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3ChannelTb4b4b4.Te6edf3RoleTb4b4b4.Te6edf3PRIMARYTb4b4b4, Te6edf3resultTff7b72[T79c0ff0Tff7b72]Tb4b4b4.Te6edf3roleTb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff0Tb4b4b4, Te6edf3resultTff7b72[T79c0ff0Tff7b72]Tb4b4b4.Te6edf3indexTb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3primaryTb4b4b4, Te6edf3resultTff7b72[T79c0ff0Tff7b72]Tb4b4b4.Te6edf3settingsTb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3ChannelTb4b4b4.Te6edf3RoleTb4b4b4.Te6edf3SECONDARYTb4b4b4, Te6edf3resultTff7b72[T79c0ff1Tff7b72]Tb4b4b4.Te6edf3roleTb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff1Tb4b4b4, Te6edf3resultTff7b72[T79c0ff1Tff7b72]Tb4b4b4.Te6edf3indexTb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3secondaryATb4b4b4, Te6edf3resultTff7b72[T79c0ff1Tff7b72]Tb4b4b4.Te6edf3settingsTb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3ChannelTb4b4b4.Te6edf3RoleTb4b4b4.Te6edf3SECONDARYTb4b4b4, Te6edf3resultTff7b72[T79c0ff2Tff7b72]Tb4b4b4.Te6edf3roleTb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff2Tb4b4b4, Te6edf3resultTff7b72[T79c0ff2Tff7b72]Tb4b4b4.Te6edf3indexTb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3secondaryBTb4b4b4, Te6edf3resultTff7b72[T79c0ff2Tff7b72]Tb4b4b4.Te6edf3settingsTb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffreplacement_list_rejects_minimum_slot_count_above_maximum_slot_countTb4b4b4(Tb4b4b4) Tb4b4b4{
Te6edf3assertFailsWithTff7b72<Te6edf3IllegalArgumentExceptionTff7b72> Tb4b4b4{
Te6edf3getChannelReplacementListTb4b4b4(
Te6edf3new Tff7b72= Te6edf3listOfTb4b4b4(Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffMainTa5d6ff"Tb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3currentSettings Tff7b72= Te6edf3emptyListTb4b4b4(Tb4b4b4)Tb4b4b4,
Te6edf3minimumSlotCount Tff7b72= T79c0ff2Tb4b4b4,
Te6edf3maximumSlotCount Tff7b72= T79c0ff1Tb4b4b4,
Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffimport_writes_all_eight_slots_with_replacement_rolesTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Tff7b72val Te6edf3radioController Tff7b72= Te6edf3FakeRadioControllerTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3radioConfigRepository Tff7b72= Te6edf3FakeRadioConfigRepositoryTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3oldSettings Tff7b72=
Te6edf3listOfTb4b4b4(
Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffOld PrimaryTa5d6ff"Tb4b4b4)Tb4b4b4,
Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffOld SecondaryTa5d6ff"Tb4b4b4)Tb4b4b4,
Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffOld TertiaryTa5d6ff"Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Tff7b72val Te6edf3importedSettings Tff7b72= Te6edf3listOfTb4b4b4(Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffImportedTa5d6ff"Tb4b4b4)Tb4b4b4, Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffPrivateTa5d6ff"Tb4b4b4)Tb4b4b4)
Te6edf3radioConfigRepositoryTb4b4b4.Te6edf3setChannelSetTb4b4b4(Te6edf3ChannelSetTb4b4b4(Te6edf3settings Tff7b72= Te6edf3oldSettingsTb4b4b4)Tb4b4b4)
Te6edf3importChannelSetTb4b4b4(
Te6edf3channelSet Tff7b72= Te6edf3ChannelSetTb4b4b4(Te6edf3settings Tff7b72= Te6edf3importedSettingsTb4b4b4)Tb4b4b4,
Te6edf3radioController Tff7b72= Te6edf3radioControllerTb4b4b4,
Te6edf3radioConfigRepository Tff7b72= Te6edf3radioConfigRepositoryTb4b4b4,
Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(Tb4b4b4(T79c0ff0.Tb4b4b4.T79c0ff7Tb4b4b4)Tb4b4b4.Te6edf3toListTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3radioControllerTb4b4b4.Te6edf3localChannelsTb4b4b4.Te6edf3map Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3index Tb4b4b4}Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(
Te6edf3listOfTb4b4b4(
Te6edf3ChannelTb4b4b4.Te6edf3RoleTb4b4b4.Te6edf3PRIMARYTb4b4b4,
Te6edf3ChannelTb4b4b4.Te6edf3RoleTb4b4b4.Te6edf3SECONDARYTb4b4b4,
Te6edf3ChannelTb4b4b4.Te6edf3RoleTb4b4b4.Te6edf3DISABLEDTb4b4b4,
Te6edf3ChannelTb4b4b4.Te6edf3RoleTb4b4b4.Te6edf3DISABLEDTb4b4b4,
Te6edf3ChannelTb4b4b4.Te6edf3RoleTb4b4b4.Te6edf3DISABLEDTb4b4b4,
Te6edf3ChannelTb4b4b4.Te6edf3RoleTb4b4b4.Te6edf3DISABLEDTb4b4b4,
Te6edf3ChannelTb4b4b4.Te6edf3RoleTb4b4b4.Te6edf3DISABLEDTb4b4b4,
Te6edf3ChannelTb4b4b4.Te6edf3RoleTb4b4b4.Te6edf3DISABLEDTb4b4b4,
Tb4b4b4)Tb4b4b4,
Te6edf3radioControllerTb4b4b4.Te6edf3localChannelsTb4b4b4.Te6edf3map Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3role Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3importedSettingsTb4b4b4, Te6edf3radioConfigRepositoryTb4b4b4.Te6edf3currentChannelSetTb4b4b4.Te6edf3settingsTb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffimport_leaves_cache_untouched_when_a_channel_write_fails_mid_sessionTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Tff7b72val Te6edf3radioController Tff7b72= Te6edf3FakeRadioControllerTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3apply Tb4b4b4{ Te6edf3failChannelWriteAfter Tff7b72= T79c0ff2 Tb4b4b4}
Tff7b72val Te6edf3radioConfigRepository Tff7b72= Te6edf3FakeRadioConfigRepositoryTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3oldSettings Tff7b72=
Te6edf3listOfTb4b4b4(
Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffOld PrimaryTa5d6ff"Tb4b4b4)Tb4b4b4,
Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffOld SecondaryTa5d6ff"Tb4b4b4)Tb4b4b4,
Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffOld TertiaryTa5d6ff"Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Tff7b72val Te6edf3importedSettings Tff7b72= Te6edf3listOfTb4b4b4(Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffImportedTa5d6ff"Tb4b4b4)Tb4b4b4, Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffPrivateTa5d6ff"Tb4b4b4)Tb4b4b4)
Te6edf3radioConfigRepositoryTb4b4b4.Te6edf3setChannelSetTb4b4b4(Te6edf3ChannelSetTb4b4b4(Te6edf3settings Tff7b72= Te6edf3oldSettingsTb4b4b4)Tb4b4b4)
T8b949e// A write failing inside the editLocalSettings session propagates out before the post-session cache
T8b949e// replace, so the local cache stays exactly as it was — nothing partially applied.
Te6edf3assertFailsWithTff7b72<Te6edf3IllegalStateExceptionTff7b72> Tb4b4b4{
Te6edf3importChannelSetTb4b4b4(
Te6edf3channelSet Tff7b72= Te6edf3ChannelSetTb4b4b4(Te6edf3settings Tff7b72= Te6edf3importedSettingsTb4b4b4)Tb4b4b4,
Te6edf3radioController Tff7b72= Te6edf3radioControllerTb4b4b4,
Te6edf3radioConfigRepository Tff7b72= Te6edf3radioConfigRepositoryTb4b4b4,
Tb4b4b4)
Tb4b4b4}
Te6edf3assertEqualsTb4b4b4(Te6edf3oldSettingsTb4b4b4, Te6edf3radioConfigRepositoryTb4b4b4.Te6edf3currentChannelSetTb4b4b4.Te6edf3settingsTb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffimport_rejects_imported_settings_beyond_slot_count_before_writingTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Tff7b72val Te6edf3radioController Tff7b72= Te6edf3FakeRadioControllerTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3radioConfigRepository Tff7b72= Te6edf3FakeRadioConfigRepositoryTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3oldSettings Tff7b72= Te6edf3listOfTb4b4b4(Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffOldTa5d6ff"Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3oversizedSettings Tff7b72= Tb4b4b4(T79c0ff0.Tb4b4b4.T79c0ff8Tb4b4b4)Tb4b4b4.Te6edf3map Tb4b4b4{ Te6edf3index Tff7b72-Tff7b72> Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffImported Tffd700$Te6edf3indexTa5d6ff"Tb4b4b4) Tb4b4b4}
Te6edf3radioConfigRepositoryTb4b4b4.Te6edf3setChannelSetTb4b4b4(Te6edf3ChannelSetTb4b4b4(Te6edf3settings Tff7b72= Te6edf3oldSettingsTb4b4b4)Tb4b4b4)
Te6edf3assertFailsWithTff7b72<Te6edf3IllegalArgumentExceptionTff7b72> Tb4b4b4{
Te6edf3importChannelSetTb4b4b4(
Te6edf3channelSet Tff7b72= Te6edf3ChannelSetTb4b4b4(Te6edf3settings Tff7b72= Te6edf3oversizedSettingsTb4b4b4)Tb4b4b4,
Te6edf3radioController Tff7b72= Te6edf3radioControllerTb4b4b4,
Te6edf3radioConfigRepository Tff7b72= Te6edf3radioConfigRepositoryTb4b4b4,
Tb4b4b4)
Tb4b4b4}
Te6edf3assertTrueTb4b4b4(Te6edf3radioControllerTb4b4b4.Te6edf3localChannelsTb4b4b4.Te6edf3isEmptyTb4b4b4(Tb4b4b4)Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3oldSettingsTb4b4b4, Te6edf3radioConfigRepositoryTb4b4b4.Te6edf3currentChannelSetTb4b4b4.Te6edf3settingsTb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffreplacement_apply_ignores_cached_settings_beyond_slot_countTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Tff7b72val Te6edf3radioController Tff7b72= Te6edf3FakeRadioControllerTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3radioConfigRepository Tff7b72= Te6edf3FakeRadioConfigRepositoryTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3oldSettings Tff7b72= Tb4b4b4(T79c0ff0.Tb4b4b4.T79c0ff9Tb4b4b4)Tb4b4b4.Te6edf3map Tb4b4b4{ Te6edf3index Tff7b72-Tff7b72> Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffOld Tffd700$Te6edf3indexTa5d6ff"Tb4b4b4) Tb4b4b4}
Tff7b72val Te6edf3importedSettings Tff7b72= Te6edf3listOfTb4b4b4(Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffImportedTa5d6ff"Tb4b4b4)Tb4b4b4)
Te6edf3radioConfigRepositoryTb4b4b4.Te6edf3setChannelSetTb4b4b4(Te6edf3ChannelSetTb4b4b4(Te6edf3settings Tff7b72= Te6edf3oldSettingsTb4b4b4)Tb4b4b4)
Te6edf3importChannelSetTb4b4b4(
Te6edf3channelSet Tff7b72= Te6edf3ChannelSetTb4b4b4(Te6edf3settings Tff7b72= Te6edf3importedSettingsTb4b4b4)Tb4b4b4,
Te6edf3radioController Tff7b72= Te6edf3radioControllerTb4b4b4,
Te6edf3radioConfigRepository Tff7b72= Te6edf3radioConfigRepositoryTb4b4b4,
Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(Tb4b4b4(T79c0ff0.Tb4b4b4.T79c0ff7Tb4b4b4)Tb4b4b4.Te6edf3toListTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3radioControllerTb4b4b4.Te6edf3localChannelsTb4b4b4.Te6edf3map Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3index Tb4b4b4}Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3importedSettingsTb4b4b4, Te6edf3radioConfigRepositoryTb4b4b4.Te6edf3currentChannelSetTb4b4b4.Te6edf3settingsTb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffreplacement_apply_normalizes_oversized_raw_import_under_limit_before_writingTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Tff7b72val Te6edf3radioController Tff7b72= Te6edf3FakeRadioControllerTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3radioConfigRepository Tff7b72= Te6edf3FakeRadioConfigRepositoryTb4b4b4(Tb4b4b4)
Te6edf3radioConfigRepositoryTb4b4b4.Te6edf3setChannelSetTb4b4b4(Te6edf3ChannelSetTb4b4b4(Te6edf3settings Tff7b72= Te6edf3listOfTb4b4b4(Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffOldTa5d6ff"Tb4b4b4)Tb4b4b4)Tb4b4b4)Tb4b4b4)
T8b949e// 9 raw entries: 7 unique valid secondaries + 2 blank placeholders -> normalizes to 7 (under the 8-slot limit).
Tff7b72val Te6edf3ch0 Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffCh0Ta5d6ff"Tb4b4b4, Te6edf3psk Tff7b72= Te6edf3byteArrayOfTb4b4b4(T79c0ff1Tb4b4b4)Tb4b4b4.Te6edf3toByteStringTb4b4b4(Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3ch1 Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffCh1Ta5d6ff"Tb4b4b4, Te6edf3psk Tff7b72= Te6edf3byteArrayOfTb4b4b4(T79c0ff2Tb4b4b4)Tb4b4b4.Te6edf3toByteStringTb4b4b4(Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3ch2 Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffCh2Ta5d6ff"Tb4b4b4, Te6edf3psk Tff7b72= Te6edf3byteArrayOfTb4b4b4(T79c0ff3Tb4b4b4)Tb4b4b4.Te6edf3toByteStringTb4b4b4(Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3ch3 Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffCh3Ta5d6ff"Tb4b4b4, Te6edf3psk Tff7b72= Te6edf3byteArrayOfTb4b4b4(T79c0ff4Tb4b4b4)Tb4b4b4.Te6edf3toByteStringTb4b4b4(Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3ch4 Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffCh4Ta5d6ff"Tb4b4b4, Te6edf3psk Tff7b72= Te6edf3byteArrayOfTb4b4b4(T79c0ff5Tb4b4b4)Tb4b4b4.Te6edf3toByteStringTb4b4b4(Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3ch5 Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffCh5Ta5d6ff"Tb4b4b4, Te6edf3psk Tff7b72= Te6edf3byteArrayOfTb4b4b4(T79c0ff6Tb4b4b4)Tb4b4b4.Te6edf3toByteStringTb4b4b4(Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3ch6 Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffCh6Ta5d6ff"Tb4b4b4, Te6edf3psk Tff7b72= Te6edf3byteArrayOfTb4b4b4(T79c0ff7Tb4b4b4)Tb4b4b4.Te6edf3toByteStringTb4b4b4(Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3raw Tff7b72= Te6edf3listOfTb4b4b4(Te6edf3ch0Tb4b4b4, Te6edf3ch1Tb4b4b4, Te6edf3ChannelSettingsTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3ch2Tb4b4b4, Te6edf3ch3Tb4b4b4, Te6edf3ChannelSettingsTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3ch4Tb4b4b4, Te6edf3ch5Tb4b4b4, Te6edf3ch6Tb4b4b4)
Te6edf3importChannelSetTb4b4b4(
Te6edf3channelSet Tff7b72= Te6edf3ChannelSetTb4b4b4(Te6edf3settings Tff7b72= Te6edf3rawTb4b4b4)Tb4b4b4,
Te6edf3radioController Tff7b72= Te6edf3radioControllerTb4b4b4,
Te6edf3radioConfigRepository Tff7b72= Te6edf3radioConfigRepositoryTb4b4b4,
Tb4b4b4)
T8b949e// Cache holds the normalized 7-entry set, not the raw 9-entry import.
Te6edf3assertEqualsTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3ch0Tb4b4b4, Te6edf3ch1Tb4b4b4, Te6edf3ch2Tb4b4b4, Te6edf3ch3Tb4b4b4, Te6edf3ch4Tb4b4b4, Te6edf3ch5Tb4b4b4, Te6edf3ch6Tb4b4b4)Tb4b4b4, Te6edf3radioConfigRepositoryTb4b4b4.Te6edf3currentChannelSetTb4b4b4.Te6edf3settingsTb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffreplacement_apply_rejects_settings_still_oversized_after_normalization_drops_placeholdersTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Tff7b72val Te6edf3radioController Tff7b72= Te6edf3FakeRadioControllerTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3radioConfigRepository Tff7b72= Te6edf3FakeRadioConfigRepositoryTb4b4b4(Tb4b4b4)
Te6edf3radioConfigRepositoryTb4b4b4.Te6edf3setChannelSetTb4b4b4(Te6edf3ChannelSetTb4b4b4(Te6edf3settings Tff7b72= Te6edf3listOfTb4b4b4(Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffOldTa5d6ff"Tb4b4b4)Tb4b4b4)Tb4b4b4)Tb4b4b4)
T8b949e// 10 raw entries: 9 genuinely unique + 1 blank placeholder. Normalization drops the blank
T8b949e// (-> 9) but the result still exceeds the 8-slot limit, so the post-normalize bounds check
T8b949e// must reject before any write or cache mutation.
Tff7b72val Te6edf3unique Tff7b72= Tb4b4b4(T79c0ff1.Tb4b4b4.T79c0ff9Tb4b4b4)Tb4b4b4.Te6edf3map Tb4b4b4{ Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffChTffd700$Te6edf3itTa5d6ff"Tb4b4b4, Te6edf3psk Tff7b72= Te6edf3byteArrayOfTb4b4b4(Tffa657itTb4b4b4.Te6edf3toByteTb4b4b4(Tb4b4b4)Tb4b4b4, T79c0ff0Tb4b4b4)Tb4b4b4.Te6edf3toByteStringTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4}
Te6edf3assertFailsWithTff7b72<Te6edf3IllegalArgumentExceptionTff7b72> Tb4b4b4{
Te6edf3importChannelSetTb4b4b4(
Te6edf3channelSet Tff7b72= Te6edf3ChannelSetTb4b4b4(Te6edf3settings Tff7b72= Te6edf3unique Tff7b72+ Te6edf3ChannelSettingsTb4b4b4(Tb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3radioController Tff7b72= Te6edf3radioControllerTb4b4b4,
Te6edf3radioConfigRepository Tff7b72= Te6edf3radioConfigRepositoryTb4b4b4,
Tb4b4b4)
Tb4b4b4}
Te6edf3assertTrueTb4b4b4(Te6edf3radioControllerTb4b4b4.Te6edf3localChannelsTb4b4b4.Te6edf3isEmptyTb4b4b4(Tb4b4b4)Tb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffreplacement_apply_uses_current_local_lora_preset_when_imported_lora_is_absentTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Tff7b72val Te6edf3radioController Tff7b72= Te6edf3FakeRadioControllerTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3radioConfigRepository Tff7b72= Te6edf3FakeRadioConfigRepositoryTb4b4b4(Tb4b4b4)
T8b949e// Device is on MEDIUM_FAST. The import omits lora_config, so identity resolution must fall
T8b949e// back to the device's current preset to detect this duplicate.
Te6edf3radioConfigRepositoryTb4b4b4.Te6edf3setLocalConfigDirectTb4b4b4(
Te6edf3LocalConfigTb4b4b4(
Te6edf3lora Tff7b72= Te6edf3ConfigTb4b4b4.Te6edf3LoRaConfigTb4b4b4(Te6edf3use_preset Tff7b72= Tff7b72trueTb4b4b4, Te6edf3modem_preset Tff7b72= Te6edf3ConfigTb4b4b4.Te6edf3LoRaConfigTb4b4b4.Te6edf3ModemPresetTb4b4b4.Te6edf3MEDIUM_FASTTb4b4b4)Tb4b4b4,
Tb4b4b4)Tb4b4b4,
Tb4b4b4)
T8b949e// Primary carries an explicit preset name; the secondary has an empty name that resolves to
T8b949e// the preset display name. Under MEDIUM_FAST the secondary resolves to "MediumFast" and
T8b949e// duplicates the primary. Under a default/LongFast fallback it would resolve to "LongFast"
T8b949e// and survive — so asserting the secondary is dropped proves the current-local preset was
T8b949e// used for identity (a regression to Config.LoRaConfig() would fail this test).
Tff7b72val Te6edf3psk Tff7b72= Te6edf3byteArrayOfTb4b4b4(T79c0ff1Tb4b4b4, T79c0ff2Tb4b4b4, T79c0ff3Tb4b4b4)Tb4b4b4.Te6edf3toByteStringTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3primary Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffMediumFastTa5d6ff"Tb4b4b4, Te6edf3psk Tff7b72= Te6edf3pskTb4b4b4)
Tff7b72val Te6edf3unnamedSecondary Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3psk Tff7b72= Te6edf3pskTb4b4b4)
Te6edf3importChannelSetTb4b4b4(
Te6edf3channelSet Tff7b72= Te6edf3ChannelSetTb4b4b4(Te6edf3settings Tff7b72= Te6edf3listOfTb4b4b4(Te6edf3primaryTb4b4b4, Te6edf3unnamedSecondaryTb4b4b4)Tb4b4b4)Tb4b4b4, T8b949e// no lora_config
Te6edf3radioController Tff7b72= Te6edf3radioControllerTb4b4b4,
Te6edf3radioConfigRepository Tff7b72= Te6edf3radioConfigRepositoryTb4b4b4,
Tb4b4b4)
T8b949e// Secondary dropped as a semantic duplicate of the primary under the device's MEDIUM_FAST preset.
Te6edf3assertEqualsTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3primaryTb4b4b4)Tb4b4b4, Te6edf3radioConfigRepositoryTb4b4b4.Te6edf3currentChannelSetTb4b4b4.Te6edf3settingsTb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffimported_lora_config_is_written_inside_the_same_transaction_when_it_differsTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Tff7b72val Te6edf3radioController Tff7b72= Te6edf3FakeRadioControllerTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3radioConfigRepository Tff7b72= Te6edf3FakeRadioConfigRepositoryTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3imported Tff7b72= Te6edf3ConfigTb4b4b4.Te6edf3LoRaConfigTb4b4b4(Te6edf3region Tff7b72= Te6edf3ConfigTb4b4b4.Te6edf3LoRaConfigTb4b4b4.Te6edf3RegionCodeTb4b4b4.Te6edf3USTb4b4b4)
Te6edf3radioConfigRepositoryTb4b4b4.Te6edf3setLocalConfigDirectTb4b4b4(
Te6edf3LocalConfigTb4b4b4(Te6edf3lora Tff7b72= Te6edf3ConfigTb4b4b4.Te6edf3LoRaConfigTb4b4b4(Te6edf3region Tff7b72= Te6edf3ConfigTb4b4b4.Te6edf3LoRaConfigTb4b4b4.Te6edf3RegionCodeTb4b4b4.Te6edf3EU_868Tb4b4b4)Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Te6edf3radioConfigRepositoryTb4b4b4.Te6edf3setChannelSetTb4b4b4(Te6edf3ChannelSetTb4b4b4(Te6edf3settings Tff7b72= Te6edf3listOfTb4b4b4(Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffOldTa5d6ff"Tb4b4b4)Tb4b4b4)Tb4b4b4)Tb4b4b4)
Te6edf3importChannelSetTb4b4b4(
Te6edf3channelSet Tff7b72= Te6edf3ChannelSetTb4b4b4(Te6edf3settings Tff7b72= Te6edf3listOfTb4b4b4(Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffImportedTa5d6ff"Tb4b4b4)Tb4b4b4)Tb4b4b4, Te6edf3lora_config Tff7b72= Te6edf3importedTb4b4b4)Tb4b4b4,
Te6edf3radioController Tff7b72= Te6edf3radioControllerTb4b4b4,
Te6edf3radioConfigRepository Tff7b72= Te6edf3radioConfigRepositoryTb4b4b4,
Tb4b4b4)
T8b949e// LoRa write is the last op in the edit session, with no settle delays around it.
Te6edf3assertEqualsTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3ConfigTb4b4b4(Te6edf3lora Tff7b72= Te6edf3importedTb4b4b4)Tb4b4b4)Tb4b4b4, Te6edf3radioControllerTb4b4b4.Te6edf3localConfigsTb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffimported_lora_config_is_not_written_when_absent_or_unchangedTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3runTest Tb4b4b4{
Tff7b72val Te6edf3current Tff7b72= Te6edf3ConfigTb4b4b4.Te6edf3LoRaConfigTb4b4b4(Te6edf3region Tff7b72= Te6edf3ConfigTb4b4b4.Te6edf3LoRaConfigTb4b4b4.Te6edf3RegionCodeTb4b4b4.Te6edf3USTb4b4b4)
Tff7b72val Te6edf3absent Tff7b72= Te6edf3FakeRadioControllerTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3absentRepo Tff7b72= Te6edf3FakeRadioConfigRepositoryTb4b4b4(Tb4b4b4)
Te6edf3absentRepoTb4b4b4.Te6edf3setLocalConfigDirectTb4b4b4(Te6edf3LocalConfigTb4b4b4(Te6edf3lora Tff7b72= Te6edf3currentTb4b4b4)Tb4b4b4)
Te6edf3absentRepoTb4b4b4.Te6edf3setChannelSetTb4b4b4(Te6edf3ChannelSetTb4b4b4(Te6edf3settings Tff7b72= Te6edf3listOfTb4b4b4(Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffOldTa5d6ff"Tb4b4b4)Tb4b4b4)Tb4b4b4)Tb4b4b4)
Te6edf3importChannelSetTb4b4b4(
Te6edf3channelSet Tff7b72= Te6edf3ChannelSetTb4b4b4(Te6edf3settings Tff7b72= Te6edf3listOfTb4b4b4(Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffImportedTa5d6ff"Tb4b4b4)Tb4b4b4)Tb4b4b4)Tb4b4b4, T8b949e// no lora_config
Te6edf3radioController Tff7b72= Te6edf3absentTb4b4b4,
Te6edf3radioConfigRepository Tff7b72= Te6edf3absentRepoTb4b4b4,
Tb4b4b4)
Tff7b72val Te6edf3unchanged Tff7b72= Te6edf3FakeRadioControllerTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3unchangedRepo Tff7b72= Te6edf3FakeRadioConfigRepositoryTb4b4b4(Tb4b4b4)
Te6edf3unchangedRepoTb4b4b4.Te6edf3setLocalConfigDirectTb4b4b4(Te6edf3LocalConfigTb4b4b4(Te6edf3lora Tff7b72= Te6edf3currentTb4b4b4)Tb4b4b4)
Te6edf3unchangedRepoTb4b4b4.Te6edf3setChannelSetTb4b4b4(Te6edf3ChannelSetTb4b4b4(Te6edf3settings Tff7b72= Te6edf3listOfTb4b4b4(Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffOldTa5d6ff"Tb4b4b4)Tb4b4b4)Tb4b4b4)Tb4b4b4)
Te6edf3importChannelSetTb4b4b4(
Te6edf3channelSet Tff7b72= Te6edf3ChannelSetTb4b4b4(Te6edf3settings Tff7b72= Te6edf3listOfTb4b4b4(Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffImportedTa5d6ff"Tb4b4b4)Tb4b4b4)Tb4b4b4, Te6edf3lora_config Tff7b72= Te6edf3currentTb4b4b4)Tb4b4b4,
Te6edf3radioController Tff7b72= Te6edf3unchangedTb4b4b4,
Te6edf3radioConfigRepository Tff7b72= Te6edf3unchangedRepoTb4b4b4,
Tb4b4b4)
Te6edf3assertTrueTb4b4b4(Te6edf3absentTb4b4b4.Te6edf3localConfigsTb4b4b4.Te6edf3isEmptyTb4b4b4(Tb4b4b4)Tb4b4b4)
Te6edf3assertTrueTb4b4b4(Te6edf3unchangedTb4b4b4.Te6edf3localConfigsTb4b4b4.Te6edf3isEmptyTb4b4b4(Tb4b4b4)Tb4b4b4)
Tb4b4b4}
T8b949e// --- getChannelPreviewForAdd tests ---
Tf0883e@Test
Tff7b72fun Td2a8ffpreview_existing_channels_are_always_shown_and_selectedTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3existing Tff7b72= Te6edf3listOfTb4b4b4(Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffATa5d6ff"Tb4b4b4)Tb4b4b4, Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffBTa5d6ff"Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3preview Tff7b72= Te6edf3getChannelPreviewForAddTb4b4b4(Te6edf3existingTb4b4b4, Te6edf3emptyListTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3ModelChannelTb4b4b4.Te6edf3defaultTb4b4b4.Te6edf3loraConfigTb4b4b4, Te6edf3maxChannels Tff7b72= T79c0ff8Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3existingTb4b4b4, Te6edf3previewTb4b4b4.Te6edf3settingsTb4b4b4)
Te6edf3assertTrueTb4b4b4(Te6edf3previewTb4b4b4.Te6edf3selectionsTb4b4b4.Te6edf3all Tb4b4b4{ Tffa657it Tb4b4b4}Tb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffpreview_unique_incoming_channels_are_shown_and_selectedTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3incoming Tff7b72= Te6edf3listOfTb4b4b4(Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffCTa5d6ff"Tb4b4b4)Tb4b4b4, Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffDTa5d6ff"Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3preview Tff7b72= Te6edf3getChannelPreviewForAddTb4b4b4(Te6edf3emptyListTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3incomingTb4b4b4, Te6edf3ModelChannelTb4b4b4.Te6edf3defaultTb4b4b4.Te6edf3loraConfigTb4b4b4, Te6edf3maxChannels Tff7b72= T79c0ff8Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3incomingTb4b4b4, Te6edf3previewTb4b4b4.Te6edf3settingsTb4b4b4)
Te6edf3assertTrueTb4b4b4(Te6edf3previewTb4b4b4.Te6edf3selectionsTb4b4b4.Te6edf3all Tb4b4b4{ Tffa657it Tb4b4b4}Tb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffpreview_incoming_duplicate_of_existing_is_omittedTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3channel Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffTestTa5d6ff"Tb4b4b4, Te6edf3psk Tff7b72= Te6edf3byteArrayOfTb4b4b4(T79c0ff1Tb4b4b4)Tb4b4b4.Te6edf3toByteStringTb4b4b4(Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3preview Tff7b72=
Te6edf3getChannelPreviewForAddTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3channelTb4b4b4)Tb4b4b4, Te6edf3listOfTb4b4b4(Te6edf3channelTb4b4b4)Tb4b4b4, Te6edf3ModelChannelTb4b4b4.Te6edf3defaultTb4b4b4.Te6edf3loraConfigTb4b4b4, Te6edf3maxChannels Tff7b72= T79c0ff8Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3channelTb4b4b4)Tb4b4b4, Te6edf3previewTb4b4b4.Te6edf3settingsTb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffpreview_duplicate_inside_incoming_keeps_first_and_omits_laterTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3a Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffATa5d6ff"Tb4b4b4, Te6edf3psk Tff7b72= Te6edf3byteArrayOfTb4b4b4(T79c0ff1Tb4b4b4)Tb4b4b4.Te6edf3toByteStringTb4b4b4(Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3b Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffBTa5d6ff"Tb4b4b4, Te6edf3psk Tff7b72= Te6edf3byteArrayOfTb4b4b4(T79c0ff2Tb4b4b4)Tb4b4b4.Te6edf3toByteStringTb4b4b4(Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3preview Tff7b72=
Te6edf3getChannelPreviewForAddTb4b4b4(Te6edf3emptyListTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3listOfTb4b4b4(Te6edf3aTb4b4b4, Te6edf3aTb4b4b4, Te6edf3bTb4b4b4)Tb4b4b4, Te6edf3ModelChannelTb4b4b4.Te6edf3defaultTb4b4b4.Te6edf3loraConfigTb4b4b4, Te6edf3maxChannels Tff7b72= T79c0ff8Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3aTb4b4b4, Te6edf3bTb4b4b4)Tb4b4b4, Te6edf3previewTb4b4b4.Te6edf3settingsTb4b4b4)
Te6edf3assertTrueTb4b4b4(Te6edf3previewTb4b4b4.Te6edf3selectionsTff7b72[T79c0ff0Tff7b72]Tb4b4b4)
Te6edf3assertTrueTb4b4b4(Te6edf3previewTb4b4b4.Te6edf3selectionsTff7b72[T79c0ff1Tff7b72]Tb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffpreview_same_name_different_psk_remains_visibleTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3existingChan Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffATa5d6ff"Tb4b4b4, Te6edf3psk Tff7b72= Te6edf3byteArrayOfTb4b4b4(T79c0ff1Tb4b4b4)Tb4b4b4.Te6edf3toByteStringTb4b4b4(Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3incomingChan Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffATa5d6ff"Tb4b4b4, Te6edf3psk Tff7b72= Te6edf3byteArrayOfTb4b4b4(T79c0ff2Tb4b4b4)Tb4b4b4.Te6edf3toByteStringTb4b4b4(Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3preview Tff7b72=
Te6edf3getChannelPreviewForAddTb4b4b4(
Te6edf3listOfTb4b4b4(Te6edf3existingChanTb4b4b4)Tb4b4b4,
Te6edf3listOfTb4b4b4(Te6edf3incomingChanTb4b4b4)Tb4b4b4,
Te6edf3ModelChannelTb4b4b4.Te6edf3defaultTb4b4b4.Te6edf3loraConfigTb4b4b4,
Te6edf3maxChannels Tff7b72= T79c0ff8Tb4b4b4,
Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff2Tb4b4b4, Te6edf3previewTb4b4b4.Te6edf3settingsTb4b4b4.Te6edf3sizeTb4b4b4)
Te6edf3assertTrueTb4b4b4(Te6edf3previewTb4b4b4.Te6edf3selectionsTff7b72[T79c0ff1Tff7b72]Tb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffpreview_same_psk_different_name_remains_visibleTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3psk Tff7b72= Te6edf3byteArrayOfTb4b4b4(T79c0ff1Tb4b4b4, T79c0ff2Tb4b4b4)Tb4b4b4.Te6edf3toByteStringTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3existingChan Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffATa5d6ff"Tb4b4b4, Te6edf3psk Tff7b72= Te6edf3pskTb4b4b4)
Tff7b72val Te6edf3incomingChan Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffBTa5d6ff"Tb4b4b4, Te6edf3psk Tff7b72= Te6edf3pskTb4b4b4)
Tff7b72val Te6edf3preview Tff7b72=
Te6edf3getChannelPreviewForAddTb4b4b4(
Te6edf3listOfTb4b4b4(Te6edf3existingChanTb4b4b4)Tb4b4b4,
Te6edf3listOfTb4b4b4(Te6edf3incomingChanTb4b4b4)Tb4b4b4,
Te6edf3ModelChannelTb4b4b4.Te6edf3defaultTb4b4b4.Te6edf3loraConfigTb4b4b4,
Te6edf3maxChannels Tff7b72= T79c0ff8Tb4b4b4,
Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff2Tb4b4b4, Te6edf3previewTb4b4b4.Te6edf3settingsTb4b4b4.Te6edf3sizeTb4b4b4)
Te6edf3assertTrueTb4b4b4(Te6edf3previewTb4b4b4.Te6edf3selectionsTff7b72[T79c0ff1Tff7b72]Tb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffpreview_empty_name_default_matches_explicit_preset_name_and_is_omittedTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3loraConfig Tff7b72= Te6edf3ModelChannelTb4b4b4.Te6edf3defaultTb4b4b4.Te6edf3loraConfig
Tff7b72val Te6edf3existingChan Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3psk Tff7b72= Te6edf3byteArrayOfTb4b4b4(T79c0ff1Tb4b4b4)Tb4b4b4.Te6edf3toByteStringTb4b4b4(Tb4b4b4)Tb4b4b4) T8b949e// resolves to "LongFast"
Tff7b72val Te6edf3incomingChan Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffLongFastTa5d6ff"Tb4b4b4, Te6edf3psk Tff7b72= Te6edf3byteArrayOfTb4b4b4(T79c0ff1Tb4b4b4)Tb4b4b4.Te6edf3toByteStringTb4b4b4(Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3preview Tff7b72= Te6edf3getChannelPreviewForAddTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3existingChanTb4b4b4)Tb4b4b4, Te6edf3listOfTb4b4b4(Te6edf3incomingChanTb4b4b4)Tb4b4b4, Te6edf3loraConfigTb4b4b4, Te6edf3maxChannels Tff7b72= T79c0ff8Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3existingChanTb4b4b4)Tb4b4b4, Te6edf3previewTb4b4b4.Te6edf3settingsTb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffpreview_explicit_preset_name_matches_empty_name_default_and_is_omittedTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3loraConfig Tff7b72= Te6edf3ModelChannelTb4b4b4.Te6edf3defaultTb4b4b4.Te6edf3loraConfig
Tff7b72val Te6edf3existingChan Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffLongFastTa5d6ff"Tb4b4b4, Te6edf3psk Tff7b72= Te6edf3byteArrayOfTb4b4b4(T79c0ff1Tb4b4b4)Tb4b4b4.Te6edf3toByteStringTb4b4b4(Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3incomingChan Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3psk Tff7b72= Te6edf3byteArrayOfTb4b4b4(T79c0ff1Tb4b4b4)Tb4b4b4.Te6edf3toByteStringTb4b4b4(Tb4b4b4)Tb4b4b4) T8b949e// resolves to "LongFast"
Tff7b72val Te6edf3preview Tff7b72= Te6edf3getChannelPreviewForAddTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3existingChanTb4b4b4)Tb4b4b4, Te6edf3listOfTb4b4b4(Te6edf3incomingChanTb4b4b4)Tb4b4b4, Te6edf3loraConfigTb4b4b4, Te6edf3maxChannels Tff7b72= T79c0ff8Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3existingChanTb4b4b4)Tb4b4b4, Te6edf3previewTb4b4b4.Te6edf3settingsTb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffpreview_psk_marker_matches_expanded_default_key_and_is_omittedTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3loraConfig Tff7b72= Te6edf3ModelChannelTb4b4b4.Te6edf3defaultTb4b4b4.Te6edf3loraConfig
Tff7b72val Te6edf3expandedPsk Tff7b72=
Te6edf3ModelChannelTb4b4b4(Te6edf3settings Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3psk Tff7b72= Te6edf3byteArrayOfTb4b4b4(T79c0ff1Tb4b4b4)Tb4b4b4.Te6edf3toByteStringTb4b4b4(Tb4b4b4)Tb4b4b4)Tb4b4b4, Te6edf3loraConfig Tff7b72= Te6edf3loraConfigTb4b4b4)Tb4b4b4.Te6edf3psk
Tff7b72val Te6edf3markerChan Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffTestTa5d6ff"Tb4b4b4, Te6edf3psk Tff7b72= Te6edf3byteArrayOfTb4b4b4(T79c0ff1Tb4b4b4)Tb4b4b4.Te6edf3toByteStringTb4b4b4(Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3expandedChan Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffTestTa5d6ff"Tb4b4b4, Te6edf3psk Tff7b72= Te6edf3expandedPskTb4b4b4)
Tff7b72val Te6edf3preview Tff7b72= Te6edf3getChannelPreviewForAddTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3markerChanTb4b4b4)Tb4b4b4, Te6edf3listOfTb4b4b4(Te6edf3expandedChanTb4b4b4)Tb4b4b4, Te6edf3loraConfigTb4b4b4, Te6edf3maxChannels Tff7b72= T79c0ff8Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3markerChanTb4b4b4)Tb4b4b4, Te6edf3previewTb4b4b4.Te6edf3settingsTb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffpreview_non_long_fast_preset_default_duplicate_is_omittedTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3loraConfig Tff7b72= Te6edf3ConfigTb4b4b4.Te6edf3LoRaConfigTb4b4b4(Te6edf3use_preset Tff7b72= Tff7b72trueTb4b4b4, Te6edf3modem_preset Tff7b72= Te6edf3ConfigTb4b4b4.Te6edf3LoRaConfigTb4b4b4.Te6edf3ModemPresetTb4b4b4.Te6edf3MEDIUM_FASTTb4b4b4)
Tff7b72val Te6edf3existingChan Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3psk Tff7b72= Te6edf3byteArrayOfTb4b4b4(T79c0ff1Tb4b4b4)Tb4b4b4.Te6edf3toByteStringTb4b4b4(Tb4b4b4)Tb4b4b4) T8b949e// resolves to "MediumFast"
Tff7b72val Te6edf3incomingChan Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffMediumFastTa5d6ff"Tb4b4b4, Te6edf3psk Tff7b72= Te6edf3byteArrayOfTb4b4b4(T79c0ff1Tb4b4b4)Tb4b4b4.Te6edf3toByteStringTb4b4b4(Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3preview Tff7b72= Te6edf3getChannelPreviewForAddTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3existingChanTb4b4b4)Tb4b4b4, Te6edf3listOfTb4b4b4(Te6edf3incomingChanTb4b4b4)Tb4b4b4, Te6edf3loraConfigTb4b4b4, Te6edf3maxChannels Tff7b72= T79c0ff8Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3existingChanTb4b4b4)Tb4b4b4, Te6edf3previewTb4b4b4.Te6edf3settingsTb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffpreview_omitted_duplicates_do_not_consume_capacityTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3existing Tff7b72= Te6edf3listOfTb4b4b4(Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffATa5d6ff"Tb4b4b4)Tb4b4b4, Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffBTa5d6ff"Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3dup Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffATa5d6ff"Tb4b4b4)
Tff7b72val Te6edf3unique Tff7b72= Te6edf3listOfTb4b4b4(Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffCTa5d6ff"Tb4b4b4)Tb4b4b4, Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffDTa5d6ff"Tb4b4b4)Tb4b4b4, Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffETa5d6ff"Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3preview Tff7b72=
Te6edf3getChannelPreviewForAddTb4b4b4(Te6edf3existingTb4b4b4, Te6edf3listOfTb4b4b4(Te6edf3dupTb4b4b4) Tff7b72+ Te6edf3uniqueTb4b4b4, Te6edf3ModelChannelTb4b4b4.Te6edf3defaultTb4b4b4.Te6edf3loraConfigTb4b4b4, Te6edf3maxChannels Tff7b72= T79c0ff5Tb4b4b4)
T8b949e// Duplicate A omitted entirely (not in settings); C, D, E all selected because the omitted dup did not consume
T8b949e// capacity.
Te6edf3assertEqualsTb4b4b4(Te6edf3listOfTb4b4b4(Ta5d6ff"Ta5d6ffATa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffBTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffCTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffDTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffETa5d6ff"Tb4b4b4)Tb4b4b4, Te6edf3previewTb4b4b4.Te6edf3settingsTb4b4b4.Te6edf3map Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3name Tb4b4b4}Tb4b4b4)
Te6edf3assertTrueTb4b4b4(Te6edf3previewTb4b4b4.Te6edf3selectionsTff7b72[T79c0ff2Tff7b72]Tb4b4b4) T8b949e// C
Te6edf3assertTrueTb4b4b4(Te6edf3previewTb4b4b4.Te6edf3selectionsTff7b72[T79c0ff3Tff7b72]Tb4b4b4) T8b949e// D
Te6edf3assertTrueTb4b4b4(Te6edf3previewTb4b4b4.Te6edf3selectionsTff7b72[T79c0ff4Tff7b72]Tb4b4b4) T8b949e// E
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffpreview_over_capacity_unique_incoming_remains_visible_but_uncheckedTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3existing Tff7b72= Te6edf3listOfTb4b4b4(Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffATa5d6ff"Tb4b4b4)Tb4b4b4, Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffBTa5d6ff"Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3incoming Tff7b72=
Te6edf3listOfTb4b4b4(
Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffCTa5d6ff"Tb4b4b4)Tb4b4b4,
Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffDTa5d6ff"Tb4b4b4)Tb4b4b4,
Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffETa5d6ff"Tb4b4b4)Tb4b4b4,
Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffFTa5d6ff"Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Tff7b72val Te6edf3preview Tff7b72= Te6edf3getChannelPreviewForAddTb4b4b4(Te6edf3existingTb4b4b4, Te6edf3incomingTb4b4b4, Te6edf3ModelChannelTb4b4b4.Te6edf3defaultTb4b4b4.Te6edf3loraConfigTb4b4b4, Te6edf3maxChannels Tff7b72= T79c0ff4Tb4b4b4)
T8b949e// All unique incoming are visible; C and D fit (4 total), E and F over capacity remain visible but unchecked.
Te6edf3assertEqualsTb4b4b4(T79c0ff6Tb4b4b4, Te6edf3previewTb4b4b4.Te6edf3settingsTb4b4b4.Te6edf3sizeTb4b4b4)
Te6edf3assertTrueTb4b4b4(Te6edf3previewTb4b4b4.Te6edf3selectionsTff7b72[T79c0ff2Tff7b72]Tb4b4b4) T8b949e// C fits
Te6edf3assertTrueTb4b4b4(Te6edf3previewTb4b4b4.Te6edf3selectionsTff7b72[T79c0ff3Tff7b72]Tb4b4b4) T8b949e// D fits
Te6edf3assertFalseTb4b4b4(Te6edf3previewTb4b4b4.Te6edf3selectionsTff7b72[T79c0ff4Tff7b72]Tb4b4b4) T8b949e// E over capacity
Te6edf3assertFalseTb4b4b4(Te6edf3previewTb4b4b4.Te6edf3selectionsTff7b72[T79c0ff5Tff7b72]Tb4b4b4) T8b949e// F over capacity
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffpreview_existing_at_max_omits_nothing_but_all_incoming_uncheckedTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3existing Tff7b72= Tb4b4b4(T79c0ff1.Tb4b4b4.T79c0ff8Tb4b4b4)Tb4b4b4.Te6edf3map Tb4b4b4{ Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffChTffd700$Te6edf3itTa5d6ff"Tb4b4b4) Tb4b4b4}
Tff7b72val Te6edf3incoming Tff7b72= Te6edf3listOfTb4b4b4(Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffNewTa5d6ff"Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3preview Tff7b72= Te6edf3getChannelPreviewForAddTb4b4b4(Te6edf3existingTb4b4b4, Te6edf3incomingTb4b4b4, Te6edf3ModelChannelTb4b4b4.Te6edf3defaultTb4b4b4.Te6edf3loraConfigTb4b4b4, Te6edf3maxChannels Tff7b72= T79c0ff8Tb4b4b4)
T8b949e// Unique incoming still visible (not a duplicate) but unchecked because capacity is full.
Te6edf3assertEqualsTb4b4b4(T79c0ff9Tb4b4b4, Te6edf3previewTb4b4b4.Te6edf3settingsTb4b4b4.Te6edf3sizeTb4b4b4)
Te6edf3assertFalseTb4b4b4(Te6edf3previewTb4b4b4.Te6edf3selectionsTff7b72[T79c0ff8Tff7b72]Tb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffpreview_settings_and_selections_are_always_size_matchedTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3existing Tff7b72= Te6edf3listOfTb4b4b4(Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffATa5d6ff"Tb4b4b4)Tb4b4b4, Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffBTa5d6ff"Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3incoming Tff7b72=
Te6edf3listOfTb4b4b4(
Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffATa5d6ff"Tb4b4b4, Te6edf3psk Tff7b72= Te6edf3byteArrayOfTb4b4b4(T79c0ff1Tb4b4b4)Tb4b4b4.Te6edf3toByteStringTb4b4b4(Tb4b4b4)Tb4b4b4)Tb4b4b4, T8b949e// duplicate of existing
Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffCTa5d6ff"Tb4b4b4)Tb4b4b4,
Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffDTa5d6ff"Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Tff7b72val Te6edf3preview Tff7b72= Te6edf3getChannelPreviewForAddTb4b4b4(Te6edf3existingTb4b4b4, Te6edf3incomingTb4b4b4, Te6edf3ModelChannelTb4b4b4.Te6edf3defaultTb4b4b4.Te6edf3loraConfigTb4b4b4, Te6edf3maxChannels Tff7b72= T79c0ff8Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3previewTb4b4b4.Te6edf3settingsTb4b4b4.Te6edf3sizeTb4b4b4, Te6edf3previewTb4b4b4.Te6edf3selectionsTb4b4b4.Te6edf3sizeTb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffpreview_both_empty_produces_empty_previewTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3preview Tff7b72=
Te6edf3getChannelPreviewForAddTb4b4b4(Te6edf3emptyListTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3emptyListTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3ModelChannelTb4b4b4.Te6edf3defaultTb4b4b4.Te6edf3loraConfigTb4b4b4, Te6edf3maxChannels Tff7b72= T79c0ff8Tb4b4b4)
Te6edf3assertTrueTb4b4b4(Te6edf3previewTb4b4b4.Te6edf3settingsTb4b4b4.Te6edf3isEmptyTb4b4b4(Tb4b4b4)Tb4b4b4)
Te6edf3assertTrueTb4b4b4(Te6edf3previewTb4b4b4.Te6edf3selectionsTb4b4b4.Te6edf3isEmptyTb4b4b4(Tb4b4b4)Tb4b4b4)
Tb4b4b4}
T8b949e// --- normalizeReplacementSettings tests ---
Tf0883e@Test
Tff7b72fun Td2a8ffnormalize_empty_list_passes_throughTb4b4b4(Tb4b4b4) Tb4b4b4{
Te6edf3assertEqualsTb4b4b4(Te6edf3emptyListTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3normalizeReplacementSettingsTb4b4b4(Te6edf3emptyListTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3ModelChannelTb4b4b4.Te6edf3defaultTb4b4b4.Te6edf3loraConfigTb4b4b4)Tb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffnormalize_single_element_passes_throughTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3primary Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffSoloTa5d6ff"Tb4b4b4, Te6edf3psk Tff7b72= Te6edf3byteArrayOfTb4b4b4(T79c0ff1Tb4b4b4)Tb4b4b4.Te6edf3toByteStringTb4b4b4(Tb4b4b4)Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3primaryTb4b4b4)Tb4b4b4, Te6edf3normalizeReplacementSettingsTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3primaryTb4b4b4)Tb4b4b4, Te6edf3ModelChannelTb4b4b4.Te6edf3defaultTb4b4b4.Te6edf3loraConfigTb4b4b4)Tb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffnormalize_drops_blank_placeholder_secondaryTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3primary Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffMainTa5d6ff"Tb4b4b4, Te6edf3psk Tff7b72= Te6edf3byteArrayOfTb4b4b4(T79c0ff1Tb4b4b4, T79c0ff2Tb4b4b4)Tb4b4b4.Te6edf3toByteStringTb4b4b4(Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3real Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffChatTa5d6ff"Tb4b4b4, Te6edf3psk Tff7b72= Te6edf3byteArrayOfTb4b4b4(T79c0ff3Tb4b4b4)Tb4b4b4.Te6edf3toByteStringTb4b4b4(Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3result Tff7b72=
Te6edf3normalizeReplacementSettingsTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3primaryTb4b4b4, Te6edf3ChannelSettingsTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3realTb4b4b4)Tb4b4b4, Te6edf3ModelChannelTb4b4b4.Te6edf3defaultTb4b4b4.Te6edf3loraConfigTb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3primaryTb4b4b4, Te6edf3realTb4b4b4)Tb4b4b4, Te6edf3resultTb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffnormalize_preserves_blank_primaryTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3blankPrimary Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3real Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffChatTa5d6ff"Tb4b4b4, Te6edf3psk Tff7b72= Te6edf3byteArrayOfTb4b4b4(T79c0ff3Tb4b4b4)Tb4b4b4.Te6edf3toByteStringTb4b4b4(Tb4b4b4)Tb4b4b4)
T8b949e// Slot 0 is always preserved, even when blank (deliberate disable signal).
Tff7b72val Te6edf3result Tff7b72= Te6edf3normalizeReplacementSettingsTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3blankPrimaryTb4b4b4, Te6edf3realTb4b4b4)Tb4b4b4, Te6edf3ModelChannelTb4b4b4.Te6edf3defaultTb4b4b4.Te6edf3loraConfigTb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff2Tb4b4b4, Te6edf3resultTb4b4b4.Te6edf3sizeTb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3blankPrimaryTb4b4b4, Te6edf3resultTff7b72[T79c0ff0Tff7b72]Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3realTb4b4b4, Te6edf3resultTff7b72[T79c0ff1Tff7b72]Tb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffnormalize_blank_primary_does_not_seed_duplicate_trackingTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3blankPrimary Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3publicSecondary Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3psk Tff7b72= Te6edf3byteArrayOfTb4b4b4(T79c0ff1Tb4b4b4)Tb4b4b4.Te6edf3toByteStringTb4b4b4(Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3result Tff7b72=
Te6edf3normalizeReplacementSettingsTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3blankPrimaryTb4b4b4, Te6edf3publicSecondaryTb4b4b4)Tb4b4b4, Te6edf3ModelChannelTb4b4b4.Te6edf3defaultTb4b4b4.Te6edf3loraConfigTb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3blankPrimaryTb4b4b4, Te6edf3publicSecondaryTb4b4b4)Tb4b4b4, Te6edf3resultTb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffnormalize_drops_semantic_duplicate_secondaryTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3primary Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffMainTa5d6ff"Tb4b4b4, Te6edf3psk Tff7b72= Te6edf3byteArrayOfTb4b4b4(T79c0ff1Tb4b4b4)Tb4b4b4.Te6edf3toByteStringTb4b4b4(Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3dup Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffMainTa5d6ff"Tb4b4b4, Te6edf3psk Tff7b72= Te6edf3byteArrayOfTb4b4b4(T79c0ff1Tb4b4b4)Tb4b4b4.Te6edf3toByteStringTb4b4b4(Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3result Tff7b72= Te6edf3normalizeReplacementSettingsTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3primaryTb4b4b4, Te6edf3dupTb4b4b4)Tb4b4b4, Te6edf3ModelChannelTb4b4b4.Te6edf3defaultTb4b4b4.Te6edf3loraConfigTb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3primaryTb4b4b4)Tb4b4b4, Te6edf3resultTb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffnormalize_keeps_same_name_different_pskTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3primary Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffATa5d6ff"Tb4b4b4, Te6edf3psk Tff7b72= Te6edf3byteArrayOfTb4b4b4(T79c0ff1Tb4b4b4)Tb4b4b4.Te6edf3toByteStringTb4b4b4(Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3other Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffATa5d6ff"Tb4b4b4, Te6edf3psk Tff7b72= Te6edf3byteArrayOfTb4b4b4(T79c0ff2Tb4b4b4)Tb4b4b4.Te6edf3toByteStringTb4b4b4(Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3result Tff7b72= Te6edf3normalizeReplacementSettingsTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3primaryTb4b4b4, Te6edf3otherTb4b4b4)Tb4b4b4, Te6edf3ModelChannelTb4b4b4.Te6edf3defaultTb4b4b4.Te6edf3loraConfigTb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3primaryTb4b4b4, Te6edf3otherTb4b4b4)Tb4b4b4, Te6edf3resultTb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffnormalize_keeps_same_psk_different_nameTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3psk Tff7b72= Te6edf3byteArrayOfTb4b4b4(T79c0ff1Tb4b4b4, T79c0ff2Tb4b4b4)Tb4b4b4.Te6edf3toByteStringTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3primary Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffATa5d6ff"Tb4b4b4, Te6edf3psk Tff7b72= Te6edf3pskTb4b4b4)
Tff7b72val Te6edf3other Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffBTa5d6ff"Tb4b4b4, Te6edf3psk Tff7b72= Te6edf3pskTb4b4b4)
Tff7b72val Te6edf3result Tff7b72= Te6edf3normalizeReplacementSettingsTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3primaryTb4b4b4, Te6edf3otherTb4b4b4)Tb4b4b4, Te6edf3ModelChannelTb4b4b4.Te6edf3defaultTb4b4b4.Te6edf3loraConfigTb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3primaryTb4b4b4, Te6edf3otherTb4b4b4)Tb4b4b4, Te6edf3resultTb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffnormalize_compacts_valid_secondaries_into_sequential_slotsTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3primary Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffMainTa5d6ff"Tb4b4b4, Te6edf3psk Tff7b72= Te6edf3byteArrayOfTb4b4b4(T79c0ff1Tb4b4b4)Tb4b4b4.Te6edf3toByteStringTb4b4b4(Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3b Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffBTa5d6ff"Tb4b4b4, Te6edf3psk Tff7b72= Te6edf3byteArrayOfTb4b4b4(T79c0ff2Tb4b4b4)Tb4b4b4.Te6edf3toByteStringTb4b4b4(Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3c Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffCTa5d6ff"Tb4b4b4, Te6edf3psk Tff7b72= Te6edf3byteArrayOfTb4b4b4(T79c0ff3Tb4b4b4)Tb4b4b4.Te6edf3toByteStringTb4b4b4(Tb4b4b4)Tb4b4b4)
T8b949e// blank + duplicate mixed in; valid B and C must compact to slots 1 and 2 with no gap
Tff7b72val Te6edf3result Tff7b72=
Te6edf3normalizeReplacementSettingsTb4b4b4(
Te6edf3listOfTb4b4b4(
Te6edf3primaryTb4b4b4,
Te6edf3ChannelSettingsTb4b4b4(Tb4b4b4)Tb4b4b4,
Te6edf3bTb4b4b4,
Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffMainTa5d6ff"Tb4b4b4, Te6edf3psk Tff7b72= Te6edf3byteArrayOfTb4b4b4(T79c0ff1Tb4b4b4)Tb4b4b4.Te6edf3toByteStringTb4b4b4(Tb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3cTb4b4b4,
Tb4b4b4)Tb4b4b4,
Te6edf3ModelChannelTb4b4b4.Te6edf3defaultTb4b4b4.Te6edf3loraConfigTb4b4b4,
Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3primaryTb4b4b4, Te6edf3bTb4b4b4, Te6edf3cTb4b4b4)Tb4b4b4, Te6edf3resultTb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffnormalize_null_lora_falls_back_to_defaults_without_crashingTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3primary Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffMainTa5d6ff"Tb4b4b4, Te6edf3psk Tff7b72= Te6edf3byteArrayOfTb4b4b4(T79c0ff1Tb4b4b4)Tb4b4b4.Te6edf3toByteStringTb4b4b4(Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3result Tff7b72= Te6edf3normalizeReplacementSettingsTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3primaryTb4b4b4, Te6edf3ChannelSettingsTb4b4b4(Tb4b4b4)Tb4b4b4)Tb4b4b4, Te6edf3loraConfig Tff7b72= Tff7b72nullTb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3primaryTb4b4b4)Tb4b4b4, Te6edf3resultTb4b4b4)
Tb4b4b4}
Tf0883e@Test
Tff7b72fun Td2a8ffnormalize_all_blank_input_preserves_only_primaryTb4b4b4(Tb4b4b4) Tb4b4b4{
T8b949e// Primary is always preserved (even blank); both blank placeholder secondaries are dropped.
Tff7b72val Te6edf3result Tff7b72=
Te6edf3normalizeReplacementSettingsTb4b4b4(
Te6edf3listOfTb4b4b4(Te6edf3ChannelSettingsTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3ChannelSettingsTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3ChannelSettingsTb4b4b4(Tb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3ModelChannelTb4b4b4.Te6edf3defaultTb4b4b4.Te6edf3loraConfigTb4b4b4,
Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff1Tb4b4b4, Te6edf3resultTb4b4b4.Te6edf3sizeTb4b4b4)
Tb4b4b4}
Tb4b4b4}
Served by rngit 1.5.0 - Generated in 0.23s